<?php
namespace Common\Model;
use Think\Db;
use Think\Model;


/**
 * 模型基类
 * Class BaseModel
 * @package app\common\model
 */
class BaseModel extends Model{
    // sql语句
	public $err_code = 0;			//错误代码
    protected $sqls = array();		//sql语句
	protected $model_name = '';		//模块名称


    //自动完成定义
    protected $_auto = array(
        array('add_time', NOW_TIME, self::MODEL_INSERT),
        array('edit_time', NOW_TIME, self::MODEL_BOTH),
    );

    /**
     * 添加时间
     * @param $value
     * @param $data
     * @return mixed
     */
    public function getAddTimeTextAttr($value, $data){
		$text = $data['add_time'] ? date('Y-m-d H:i:s',$data['add_time']) : '--';
		return $text;
    }

    /**
     * 编辑时间
     * @param $value
     * @param $data
     * @return mixed
     */
    public function getEditTimeTextAttr($value, $data){
		$text = $data['edit_time'] ? date('Y-m-d H:i:s',$data['edit_time']) : '--';
		return $text;
    }

    /**
     * 状态
     * @param $value
     * @param $data
     * @return mixed
     */
    public function getStatusTextAttr($value, $data){
		$status_text = '--';
		if($data['status']==1){
			$status_text = '正常';
		}else if($data['status']==0){
			$status_text = '关闭';
		}
		return $status_text;
    }

    /**
     * 图片
     * @param $value
     * @param $data
     * @return mixed
     */
    public function getPicAttr($value){
        $pic_url = '';
        if($value){
            $preg = "/^http(s)?:\\/\\/.+/";
            if(preg_match($preg,$value)){
                $pic_url =  $value;//完整url
            }else{
                $model = M('System');
                $vo = $model->find();
                $Wimgurl = $vo['sUrl'];
                $pic_url =  $Wimgurl.'/'.$value;
            }
        }
        return $pic_url;
    }

    //发票类型
    function getInvoiceTypeNameAttr($val, $data){
        $array = [
            0=>'不开发票',
            1=>'普通发票',
            2=>'增值税发票',
        ];
        $text = $array[$data['invoice_type']];
        return $text ? : '';
    }

    //用户表基本信息
    function getUbaseAttr($val, $data){
        $model = M('User');
        $wdata['uid'] = $data['uid'];
        $user = $model->where($wdata)->find();
        $user['amount'] = floatval($user['amount']);
        $user['credit'] = floatval($user['credit']);
        unset($user['password']);
        return $user;
    }

    /**
     * 模型基类初始化
     */
    public function _initialize(){
        parent::_initialize();
		//$model_name = str_ireplace('Model','',basename(str_replace('\\','/',get_class($this))));//子类名
		$this->model_name = $this->getModelName();
    }

    /**
     * 获取当前调用的模块名称
     * 例如：admin, api, store, task
     * @return string|bool
     */
    protected static function getCalledModule(){
        return MODULE_NAME;
    }

	 /**
     +----------------------------------------------------------
     * 列表信息
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param array $map 查询数据
     +----------------------------------------------------------
     * @return boolen
     +----------------------------------------------------------
     */
	public function getList($map = array(), $listRows=10 ,$_order_sort =''){
        //生成查询条件
        //列表过滤器，生成查询Map对象
        $map = $map ? $map : $this->_search();
        if (method_exists($this, '_filter')) {
            $this->_filter($map);
        }
		$data = $this->_list($this, $map, $listRows ,$_order_sort);
		return $data;
	}

    /**
     +----------------------------------------------------------
     * 根据表单生成查询条件
     * 进行列表过滤
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param string $name 数据对象名称
     +----------------------------------------------------------
     * @return HashMap
     +----------------------------------------------------------
     * @throws ThinkExecption
     +----------------------------------------------------------
     */
    public function _search($name = '') {
        $request = I('request.');
        //生成查询条件
		$model = $this;
        $map = array();
        $fileds = $model->getDbFields();
		//前置执行
		if(method_exists($model,'_before_search')){
			$map = $this->_before_search();
		}
        
        //有软删除字段,列表不显示
        if(in_array('is_del',$fileds)){
            $map['is_del'] = 0;
        }
        //来自ipad 
        if(in_array('uid',$fileds) && MODULE_NAME=='Apipad'){
             $map['uid'] = UID;
        }
        //dump($fileds);exit;
        foreach ($fileds as $key => $val) {
            if (isset($request [$val]) && $request [$val] !== '') {
                if (C('DB_LIKE_FIELDS')) {
                    $like_keys = explode('|', C('DB_LIKE_FIELDS'));
                    if (in_array($val, $like_keys)) {
                        $map [$val] = array('like', '%' . $request [$val] . '%');
                    } else {
                        $map [$val] = trim($request [$val]);
                    }
                } else {
                    $ar = explode(',',$_REQUEST [$val]);
                    if(count($ar)>1){
                        $map [$val] = array('in',$ar);
                    }else{
                        $map [$val] = $_REQUEST [$val];
                    }
                    //$map [$val] = trim($request [$val]);
                }
            }
        }
		//后置执行
		if(method_exists($model,'_after_search')){
			$_after_map = $this->_after_search();
			if($_after_map)$map = array_merge($map,$_after_map);
		}
        //dump($model->getDbFields());dump($map);exit;
        return $map;
    }

    /**
     +----------------------------------------------------------
     * 根据表单生成查询条件
     * 进行列表过滤
     +----------------------------------------------------------
     * @access protected
     +----------------------------------------------------------
     * @param Model $model 数据对象
     * @param HashMap $map 过滤条件
     * @param int $listRows 每页显示数量
	 * @param string $sortBy 排序
	 * @param string $field 返回字段
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public function _list($model, $map, $listRows='' ,$sortBy ='' , $field='*') {
        $model = $model ? $model : M($this->model_name);
        $request = I('request.');
        //排序字段 默认为主键名
        if($sortBy){
            //自定义
            $order = $sortBy;
        }else{
            $order = $this->getOrder($model);
        }
        if($map['no_execute']){
            //不查询
             $data['list'] = [];
            $data['page_count'] = 0;//总页数
            $data['count'] = 0;//总条数
            $data['limit'] = 0;//总条数
            $data['now_page'] = 0;
            return $data;
        }
        //取得满足条件的记录数
        $count = $model->where($map)->count();
        //echo M()->_sql();exit;
        if (!empty($request ['limit'])) {
            $listRows = $request ['limit'];
        }else if(!$listRows){
            if(MODULE_NAME=='Api'){
                $listRows = 20;
            }else{
                $listRows = C('listRows') ? C('listRows') : 100;
            }
        }
		$listRows = $listRows>500 ? 500 : $listRows;
        $page_count = ceil($count / $listRows);
        if ($count > 0) {
            //创建分页对象
            $p = new \Think\AdminPage($count, $listRows);
            //分页查询数据
            $voList = $model->field($field)->where($map)->order($order)->limit($p->firstRow . ',' . $p->listRows)->select();
          
            //分页跳转的时候保证查询条件
            foreach ($map as $map_key => $map_val) {
                if (!is_array($map_val)) {
                    //$p->parameter .= "$map_key=" . urlencode($map_val) . "&";
                }
            }
            //格式化数据
            if (method_exists($this, 'listFormat')) {
                $voList = $this->listFormat($voList);
            }
            //分页显示
            $page = $p->show();

            //列表排序显示
            $sortImg = $sort; //排序图标
            $sortAlt = $sort == 'desc' ? '升序排列' : '倒序排列'; //排序提示
            $sort = $sort == 'desc' ? 1 : 0; //排序方式
        }else{
			$p = new \Think\AdminPage($count, $listRows);
			$voList = [];
			$page = $p->show();
		}
        $data['list'] = $voList;
        if(MODULE_NAME!='Api' && MODULE_NAME!='Apipad'){
            $data['page'] = $page;
        }
        //$data['map'] = $map;
		$data['page_count'] = $p->totalPages;//总页数
		$data['count'] = $p->totalRows;//总条数
        $data['limit'] = $p->listRows;//总条数
		$data['now_page'] = $p->nowPage;
        return $data;
    }

    /**
     * 查询数据 (重写)
     * @access public
     * @param mixed $options 表达式参数
     * @return mixed
     */
    public function find($options=array()) {
        if(is_numeric($options) || is_string($options)) {
            $where[$this->getPk()]  =   $options;
            $options                =   array();
            $options['where']       =   $where;
        }
        // 根据复合主键查找记录
        $pk  =  $this->getPk();
        if (is_array($options) && (count($options) > 0) && is_array($pk)) {
            // 根据复合主键查询
            $count = 0;
            foreach (array_keys($options) as $key) {
                if (is_int($key)) $count++; 
            } 
            if ($count == count($pk)) {
                $i = 0;
                foreach ($pk as $field) {
                    $where[$field] = $options[$i];
                    unset($options[$i++]);
                }
                $options['where']  =  $where;
            } else {
                return false;
            }
        }
        // 总是查找一条记录
        $options['limit']   =   1;
        // 分析表达式
        $options            =   $this->_parseOptions($options);
        // 判断查询缓存
        if(isset($options['cache'])){
            $cache  =   $options['cache'];
            $key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options));
            $data   =   S($key,'',$cache);
            if(false !== $data){
                $this->data     =   $data;
                return $data;
            }
        }
        $resultSet          =   $this->db->select($options);
        if(false === $resultSet) {
            return false;
        }
        if(empty($resultSet)) {// 查询结果为空
            return null;
        }
        if(is_string($resultSet)){
            return $resultSet;
        }

        // 读取数据后的处理
        $data   =   $this->_read_data($resultSet[0]);
        $this->_after_find($data,$options);
        if(!empty($this->options['result'])) {
            return $this->returnResult($data,$this->options['result']);
        }

		//zzy
		if (!empty($this->append)) {
			if($this->append_ext){
				$this->append = array_merge($this->append,$this->append_ext);
			}
			foreach ($this->append as $key => $name) {
				// 检测属性获取器
				$method = 'get' . $this->camelize($name) . 'Attr';
				$value = $data[$name] ? $data[$name] : null;
				if (method_exists($this, $method)) {
					$value = $this->$method($value, $data);
					$data[$name] = $value;
				}
			}
		}
		//zzy
		if (!empty($this->hidden)) {
			foreach($data as $field=>$val){
				if(in_array($field,$this->hidden)){
					unset($data[$field]);
				}
			}
		}
        $this->data     =   $data;
        if(isset($cache)){
            S($key,$data,$cache);
        }
        return $this->data;
    }

    /**
     * 查询数据集 (重写)
     * @access public
     * @param array $options 表达式参数
     * @return mixed
     */
    public function select($options=array()) {
        $pk   =  $this->getPk();
        if(is_string($options) || is_numeric($options)) {
            // 根据主键查询
            if(strpos($options,',')) {
                $where[$pk]     =  array('IN',$options);
            }else{
                $where[$pk]     =  $options;
            }
            $options            =  array();
            $options['where']   =  $where;
        }elseif (is_array($options) && (count($options) > 0) && is_array($pk)) {
            // 根据复合主键查询
            $count = 0;
            foreach (array_keys($options) as $key) {
                if (is_int($key)) $count++; 
            } 
            if ($count == count($pk)) {
                $i = 0;
                foreach ($pk as $field) {
                    $where[$field] = $options[$i];
                    unset($options[$i++]);
                }
                $options['where']  =  $where;
            } else {
                return false;
            }
        } elseif(false === $options){ // 用于子查询 不查询只返回SQL
        	$options['fetch_sql'] = true;
        }
        // 分析表达式
        $options    =  $this->_parseOptions($options);
        // 判断查询缓存
        if(isset($options['cache'])){
            $cache  =   $options['cache'];
            $key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options));
            $data   =   S($key,'',$cache);
            if(false !== $data){
                return $data;
            }
        }
        $resultSet  = $this->db->select($options);
        if(false === $resultSet) {
            return false;
        }
        if(!empty($resultSet)) { // 有查询结果
            if(is_string($resultSet)){
                return $resultSet;
            }

            $resultSet  =   array_map(array($this,'_read_data'),$resultSet);
            $this->_after_select($resultSet,$options);
            if(isset($options['index'])){ // 对数据集进行索引
                $index  =   explode(',',$options['index']);
                foreach ($resultSet as $result){
                    $_key   =  $result[$index[0]];
                    if(isset($index[1]) && isset($result[$index[1]])){
                        $cols[$_key] =  $result[$index[1]];
                    }else{
                        $cols[$_key] =  $result;
                    }
                }
                $resultSet  =   $cols;
            }
			//zzy 属性追加 2019/11/20
			if (!empty($this->append)) {
                
				if($this->append_ext){
					$this->append = array_merge($this->append,$this->append_ext);
				}
				foreach($resultSet as &$vo){
					foreach ($this->append as $key => $name) {
						// 检测属性获取器
						$method = 'get' . $this->camelize($name) . 'Attr';
						$value = $vo[$name] ? $vo[$name] : null;
						if (method_exists($this, $method)) {
							$value = $this->$method($value, $vo);
							$vo[$name] = $value;
						}
					}
				}
			}
			//zzy 属性隐藏 2019/12/6
			if (!empty($this->hidden)) {
				foreach($resultSet as &$vo){
					foreach($vo as $field=>$val){
						if(in_array($field,$this->hidden)){
							unset($vo[$field]);
						}
					}
				}
			}

        }

        if(isset($cache)){
            S($key,$resultSet,$cache);
        }
        return $resultSet;
    }

    //组装排序字段
    function getOrder($model){
       $request = I('request.');
       if($request['_orderby']){
           $order = $request['_orderby'];
       }else if(!$request ['_order'] || !$request ['_sort']){
            //模式排序
            if($this->sortBy){
                //默认排序方法
                $order = $this->sortBy;
            }else{
                if(is_array($model->getPk())){
                    $_order =  end($model->getPk());
                }else{
                    $_order = $model->getPk();
                }
                $_sort = $asc ? 'asc' : 'desc';
                $order = "`" . $_order . "` " . $_sort;
            } 
        }else{
            //传参拼接
            if ($request ['_order']) {
                $_order = $request ['_order'];
            } else {
                if(is_array($model->getPk())){
                    $_order =  end($model->getPk());
                }else{
                    $_order = $model->getPk();
                }
            }
            //排序方式默认按照倒序排列
            //接受 sost参数 0 表示倒序 非0都 表示正序
            if ($request ['_sort']) {
                if(is_numeric($request ['_sort'])==true){
                    $_sort = $request ['_sort'] ? 'asc' : 'desc';
                }else{
                    $_sort = $request ['_sort']=='asc' ? 'asc' : 'desc';
                }
            } else {
                $_sort = $asc ? 'asc' : 'desc';
            }
            $order = "`" . $_order . "` " . $_sort;
        }
        return $order;
    }

	/**
     +----------------------------------------------------------
     * 基本信息
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param int $id 主键值
	 * @param string $field 返回字段
     +----------------------------------------------------------
     * @return $vo
     +----------------------------------------------------------
     */
	public function basic($id, $field='*'){
		$pk = $this->getPk();
        $wdata[$pk] = $id;
        $vo = $this->field($field)->where($wdata)->find();
        return $vo;
	}

	/**
     +----------------------------------------------------------
     * 详情信息
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param int $id 主键值
     +----------------------------------------------------------
     * @return $vo
     +----------------------------------------------------------
     */
	public function detail($id){
        $vo = $this->basic($id);
        return $vo;
	}

    /**
     * 检查是否有文件上传
     */
    public function checkFileUp() {
        foreach ($_FILES as $key => $val) {
            if ($val['name']) {
                return true;
            }
        }
        return false;
    }

	/**
     * 获取sql语句
     * @return array
     */
    public function getSqls(){
        return $this->sqls;
    }

	/**
     * 是否存在错误
     * @return bool
     */
    public function hasError(){
        return !empty($this->error);
    }

   /**
     * 删除原图和压缩图
     * 
     * @param $pic  压缩图路径
     * @param $org_pic 默认空，表示使用压缩图的路径获取原图片的路径
     * return voild
     */
    public function delPic($pic, $org_pic = ''){
         //删除老图片
        $upload = new \Think\Upload();
        if(is_array($pic)){
            foreach($pic as $key=>$val){
               $r = $upload->fdel($val);
            }
        }else{
            $r = $upload->fdel($pic);
        }
        return true;
    }


    /**
     * 下划线转驼峰
     * 思路:
     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
     */
    function camelize($uncamelized_words, $type=1){
        if($type==0){
            $uncamelized_words = '_'. str_replace('_', " ", strtolower($uncamelized_words));
        }else{
            $uncamelized_words = str_replace('_', " ", strtolower($uncamelized_words));
        }
        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), '_' );
    }

    /**
     * 驼峰命名转下划线命名
     * 思路:
     * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
     */
    function uncamelize($camelCaps,$separator='_'){
        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
    }


}
